rest-framework 中文文档
rest-framework框架的介绍
- rest-framework 是根据 RESTful 规范开发出来的一套 Django 的 API 框架
- rest-framework 是建立在CBV基础上使用的 -> 通俗理解: 如果要是用 rest-framework,那么就一定要使用 CBV 去编写视图
- rest-framework 的作用: 开发符合 RESTful 规范的接口
- rest-framework 的10个功能(按请求顺序排序): 路由 视图 版本 认证 权限 频率 解析器 序列化 分页 渲染器
csrf token 的问题
- 在使用 rest-framework 编写接口的时候会默认忽略掉 csrf token 认证中间件
- 原理: 在 .as_view() 返回 view 视图函数的时候会在 view 视图函数上加上 csrf_exempt 装饰器,使其忽略 csrf token 的认证

- 如果在编写接口的时候还是发生了 csrf token 问题的解决办法
- 问题一: Postman 可以正常发送请求,但是在浏览器上无法正常发送
- 解决办法一: 以 vue 项目为例: 查看 cookie 中是否存在 csrf token 的相关 cookie,如果存在清楚浏览器所有 cookie 即可
- 解决办法二: 以 vue 项目为例: 先注释掉 csrf token 中间件,然后查看浏览器是否可以正常发送请求,如果可以,删除掉 csrf token 中间件的注释,给视图类下的视图函数单独添加 csrf_exempt 装饰器
from rest_framework.views import APIView
from rest_framework.response import Response
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
class Test(APIView):
@method_decorator(csrf_exempt) # 给类里面的方法加装饰器 需要导入一个方法method_decorator
def post(self, request):
return Response({'a': 1})
- 问题一: Postman 可以无法发送请求,浏览器上也无法正常发送
- 解决办法: 先注释掉 csrf token 中间件,然后查看Postman是否可以正常发送请求,如果可以,删除掉 csrf token 中间件的注释,给视图类下的视图函数单独添加 csrf_exempt 装饰器
本笔记本所使用的数据库
# models.py
from django.db import models
class User(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
type_choices = ((1, '普通用户'), (2, 'VIP'), (3, 'SVIP'))
user_type = models.IntegerField(choices=type_choices, default=1)
def __str__(self):
return self.username
class Meta:
verbose_name = "用户表"
verbose_name_plural = verbose_name
class Token(models.Model):
user = models.OneToOneField(to='User')
token = models.CharField(max_length=128)
def __str__(self):
return self.token
class Meta:
verbose_name = "Token表"
verbose_name_plural = verbose_name
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name='书名')
price = models.IntegerField(verbose_name='价格')
pub_date = models.DateField(verbose_name='出版日期')
production_date = models.DateTimeField(verbose_name='生产日期', null=True)
publish = models.ForeignKey("Publish", verbose_name='出版社')
authors = models.ManyToManyField("Author", verbose_name='作者')
def __str__(self):
return self.title
class Meta:
verbose_name = "书籍表"
verbose_name_plural = verbose_name
class Publish(models.Model):
name = models.CharField(max_length=32, verbose_name='出版社名称')
email = models.EmailField(verbose_name='邮箱')
def __str__(self):
return self.name
class Meta:
verbose_name = "出版社表"
verbose_name_plural = verbose_name
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name='姓名')
age = models.IntegerField(verbose_name='年龄')
def __str__(self):
return self.name
class Meta:
verbose_name = "作者表"
verbose_name_plural = verbose_name
rest-framework 的下载与配置
1. 下载 rest-framework
pip3 install djangorestframework -i https://pypi.douban.com/simple # 使用豆瓣的镜像
2. 注册 rest-framework
# settings.py
INSTALLED_APPS = [
……
'rest_framework',
]
接口类的编写规范
- 在编写接口的时候要注意不能出现异常导致程序运行中断,而是使用 try 对异常进行捕获防治程序运行中断
- 编写好每个异常的状态码(即: code),每个状态码就代表着一个错误信息
- 注意: 在本章节中只有这里使用了接口类编写规范,其他栏目没有使用需要注意,且一定要按照该规范编写
# response.py
# 返回给前端的数据结构
class BaseResponse(object):
def __init__(self):
self.code = 0
self.data = None
self.msg = ''
@property
def dic(self):
return self.__dict__
# exceptions.py
# 自定义异常类
class CommonException(Exception):
def __init__(self, code, msg):
self.code = code
self.msg = msg
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from django.core.exceptions import ObjectDoesNotExist # 如果查询不到数据会抛出该错误
from api.utils.response import BaseResponse
from api.utils.exceptions import CommonException # 自定义异常类
class Spec(APIView):
def get(self):
res = BaseResponse()
try:
obj1 = 表类.objects.get(pk=xxx) # .get() 方法如果查询不到就会抛出 ObjectDoesNotExist 异常
obj2 = 表类.objects.filter(pk=xxx).first() # 如果查询不到不会抛出异常,只会返回 None
if not obj2:
raise CommonException(1002, 'xxx不存在2')
res.data = {
'xxx': obj1.xxx,
'xxx': obj2.xxx
}
except ObjectDoesNotExist as e:
res.msg = 'xxx不存在1'
res.code = 1001
except CommonException as e:
res.msg = e.msg
res.code = e.code
except Exception as e:
print(e)
# 捕获其他不知道的异常,然后写入日志中
return Response(res.dic)
APIView 的 request 对象
1. APIView 的 request对象 说明
- 这里所指的request对象就是 FBV 或 CBV 中的 request 对象
- APIView(在 rest-framework 中 CBV 所要继承的类) 的 request 对象是在 View(即: 以前CBV中所继承的类) 的 request 对象的基础上进行封装的,所以在使用在使用 rest-framework 中的 CBV 里的 request 对象是一个全新的 request 对象
- View 的 request 对象有的功能,APIView 的 request 对象都有
2. APIView 的 request对象 所提供的常用属性:
- request.GET -> 获取GET请求参数
# views.py
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
class BookView(APIView):
def get(self, request):
get_data = request.GET
# 等同于
# get_data = request._request.GET
print(get_data) # <QueryDict: {'b': ['2'], 'a': ['1']}>
return HttpResponse('get请求')
- request.query_params -> 获取GET请求参数
- request.query_params 等同于 request.GET
- request.query_params 实际上是执行了 request._request.GET
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
class BookView(APIView):
def get(self, request):
get_data = request.query_params
print(get_data) # <QueryDict: {'name': ['三国演义'], 'price': ['100']}>
print(get_data.get('name')) # 三国演义
print(get_data.get('price')) # 100
return HttpResponse('get请求')
- request.data -> 获取除GET请求外的其他请求参数(即: POST/PUT/PATCH 等请求的参数)
- 在不使用 rest-framework 之前,request.POST 只能获取以 application/x-www-form-urlencoded 编码格式发送过来的数据,其他编码格式发送过来的数据(如: application/json)都只能通过 request.body 获取,然后自行解析,但是在 rest-framework 可以通过 request.data 获取不同编码格式发送过来的数据,并且帮我们进行解析
# views.py
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
class BookView(APIView):
def post(self, request):
data = request.data
print(data) # 以 application/json 编码格式提交过来的数据 -> {'name': 'Kevin', 'age': 18}
return HttpResponse('post请求')
- request._request -> 获取 View 的 request 对象(即: 旧的request对象)
# views.py
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
class BookView(APIView):
def get(self, request):
get_data = request._request.GET
print(get_data) # <QueryDict: {'b': ['2'], 'a': ['1']}>
return HttpResponse('get请求')
def post(self, request):
post_data = request._request.POST
print(post_data) # <QueryDict: {'age': ['18'], 'name': ['Kevin']}>
return HttpResponse('post请求')